Authoring animations in markup is similar to authoring them in code, at least for simple, straightforward animation sequences. When you need to capture more complex animations, which may involve changing the values of numerous properties at once, the amount of markup can grow considerably. Thankfully, the Expression Blend animation editors can take care of the details for us. Even so, it is important to know the basics of how an animation is represented in XAML, as this will make it easier for you to modify and tweak tool-generated content.
Note You will find a number of XAML files in the XamlAnimations folder of the downloadable source code. As you go through the next several pages, copy these markup files into your custom XAML editor, or into the kaxaml editor, to see the results.
For the most part, creating an animation is similar to what you have already seen. You still configure an Animation object and associate it to an object’s property. One big difference, however, is that WPF is not function-call-friendly. As a result, instead of calling BeginAnimation(), you use a storyboard as a layer of indirection.
Let’s walk through a complete example of an animation defined in terms of XAML, followed by a detailed breakdown. The following XAML definition will display a window that contains a single label. As soon as the Label object loads into memory, it begins an animation sequence in which the font size increases from 12 points to 100 over a period of four seconds. The animation will repeat for as long as the Window object is loaded in memory. You can find this markup in the GrowLabelFont.xaml file, so copy it into your MyXamlPad.exe application and observe the behavior.
<Window xmlns="http://schemas.microsoft.com/win fx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="200" Width="600" WindowStartupLocation="CenterScreen" Title="Growing Label Font!"> <StackPanel> <Label Content = "Interesting..."> <Label.Triggers> <EventTrigger RoutedEvent = "Label.Loaded"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard TargetProperty = "FontSize"> <DoubleAnimation From = "12" To = "100" Duration = "0:0:4" RepeatBehavior = "Forever"/> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> </Label.Triggers> </Label> </StackPanel> </Window>
Now, lets break this example down bit-by-bit.
Working from the innermost element outward, we first encounter the <DoubleAnimation> element, which makes use of the same properties we set in procedural code (To, From, Duration, and RepeatBehavior):
<DoubleAnimation From = "12" To = "100" Duration = "0:0:4" RepeatBehavior = "Forever"/>
As mentioned, Animation elements are placed within a <Storyboard> element, which is used to map the animation object to a given property on the parent type via the TargetProperty property—which in this case is FontSize. A <Storyboard> is always wrapped in a parent element named <BeginStoryboard>, which is little more than a way to denote a storyboard’s location:
<BeginStoryboard> <Storyboard TargetProperty = "FontSize"> <DoubleAnimation From = "12" To = "100" Duration = "0:0:4" RepeatBehavior = "Forever"/> </Storyboard> </BeginStoryboard>
Once the <BeginStoryboard> element has been defined, we need to specify some sort of action that will cause the animation to begin executing. WPF has a few different ways to respond to runtime conditions in markup, one of which is termed a trigger. From a high level, you can consider a trigger a way of responding to an event condition in XAML, without the need for procedural code.
Typically, when you respond to an event in C#, you author custom code that will execute when the event occurs. A trigger, however, is just a way to be notified that some event condition has happened (“I’m loaded into memory”, “The mouse is over me!”, “I have focus!”).
Once you’ve been notified that an event condition has occurred, you can start the storyboard. In this example, we are responding to the Label being loaded into memory. Because it is the Label’s Loaded event we are interested in, the <EventTrigger> is placed in the Label’s trigger collection:
<Label Content = "Interesting..."> <Label.Triggers> <EventTrigger RoutedEvent = "Label.Loaded"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard TargetProperty = "FontSize"> <DoubleAnimation From = "12" To = "100" Duration = "0:0:4" RepeatBehavior = "Forever"/> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> </Label.Triggers> </Label>
Let’s see another example of defining an animation in XAML, this time using a key frame animation.
Unlike the linear interpolation animation objects, which can only move between a starting point and an ending point, the key frame counterparts allow us to create a collection of specific values for an animation that should take place at specific times.
To illustrate the use of a discrete key frame type, assume you wish to build a Button control that animates its content so that over the course of three seconds, the value “OK!” appears, one character at a time. You’ll find the following markup in the StringAnimation.xaml file. Copy this markup into your MyXamlPad.exe program and view the results:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="100" Width="300" WindowStartupLocation="CenterScreen" Title="Animate String Data!"> <StackPanel> <Button Name="myButton" Height="40" FontSize="16pt" FontFamily="Verdana" Width = "100"> <Button.Triggers> <EventTrigger RoutedEvent="Button.Loaded"> <BeginStoryboard> <Storyboard> <StringAnimationUsingKeyFrames RepeatBehavior = "Forever" Storyboard.TargetName="myButton" Storyboard.TargetProperty="Content" Duration="0:0:3"> <DiscreteStringKeyFrame Value="" KeyTime="0:0:0" /> <DiscreteStringKeyFrame Value="O" KeyTime="0:0:1" /> <DiscreteStringKeyFrame Value="OK" KeyTime="0:0:1.5" /> <DiscreteStringKeyFrame Value="OK!" KeyTime="0:0:2" /> </StringAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger> </Button.Triggers> </Button> </StackPanel> </Window>
Notice first of all that we have defined an event trigger for our button to ensure that our storyboard executes when the button has loaded into memory. The StringAnimationUsingKeyFrames class is in charge of changing the content of the button, via the Storyboard.TargetName and Storyboard.TargetProperty values.
Within the scope of the <StringAnimationUsingKeyFrames> element, we defined four DiscreteStringKeyFrame elements, which change the button’s Content property over the course of two seconds (note that the duration established by StringAnimationUsingKeyFrames is a total of three seconds, so we will see a slight pause between the final “!” and looping “O”).
Now that you have a better feel for how to build animations in C# code and XAML, let’s turn our attention of the role of WPF styles, which make heavy use of graphics, object resources, and animations.
Source Code These loose XAML files can be found under the XamlAnimations subdirectory of Chapter 30.